﻿//-----------------------------------------------------------------------
// <copyright file="ExtractPublicKey.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation.  All rights reserved.
// THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY 
// KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
// </copyright>
// <author>Andy Reeves</author>
// <email>andyr</email>
// <date>2004-03-23</date>
// <summary></summary>
//-----------------------------------------------------------------------

namespace Microsoft.Sdc.Tasks.Tools.StrongName
{
    using System;
    using System.IO;
    using System.Xml;
    using System.Globalization;
    using System.Reflection;
    using Microsoft.Win32;
    using Microsoft.Build.Framework;
    using Microsoft.Build.Tasks;
    using Microsoft.Build.Utilities;
    using System.Security.Cryptography;

    public sealed class ExtractPublicKey : ToolTaskBase
    {
        /// <summary>
        /// Initializes a new instance of the ExtractPublicKey class.
        /// </summary>
        public ExtractPublicKey()
        {
        }

        /// <summary>The path to the public snk file to extract</summary>
        [Required]
        public string DestinationKeyFile
        {
            get { return (string)Bag["DestinationKeyFile"]; }
            set { Bag["DestinationKeyFile"] = value; }
        }

        /// <summary>The public key token</summary>
        [Output]
        public string PublicKeyToken
        {
            get { return (string)Bag["PublicKeyToken"]; }
            set { Bag["PublicKeyToken"] = value; }
        }

        /// <summary>The path to the public/private snk file to extract from</summary>
        [Required]
        public string SourceKeyFile
        {
            get { return (string)Bag["SourceKeyFile"]; }
            set { Bag["SourceKeyFile"] = value; }
        }

        /// <summary>The runtime version to use for the signing i.e. 1.0, 1.1 or 2.0 </summary>
        [Required]
        public string Runtime
        {
            get { return (string)Bag["Runtime"]; }
            set { Bag["Runtime"] = value; }
        }

        /// <summary>
        /// The name of the exe we call.
        /// </summary>
        /// <value>The name of the exe we call.</value>
        protected override string ToolName
        {
            get { return "Sn.exe"; }
        }

        /// <summary>
        /// Full calculated path to tool including exe name
        /// </summary>
        /// <returns>Defaults to default install location of Sn.exe</returns>
        protected override string GenerateFullPathToTool()
        {
            string pathToTool = Path.Combine(Microsoft.Sdc.Tasks.Configuration.Utilities.GetPathToSDK(this.Runtime), @"bin\" + this.ToolName);

            if (pathToTool == null)
            {
                Log.LogError("StrongName.NotFound");
            }
            return pathToTool;
        }        

         /// <summary>
        /// Performs the action of this task.
        /// </summary>
        protected override void InternalExecute()
        {
            Log.LogMessageFromResources(MessageImportance.Low, "StrongName.ExtractingPublicKey", this.SourceKeyFile);

            CommandLineBuilder commandLine = new CommandLineBuilder();
            commandLine.AppendSwitch("-q");
            commandLine.AppendSwitch("-p");
            commandLine.AppendFileNameIfNotNull(this.SourceKeyFile);
            commandLine.AppendFileNameIfNotNull(this.DestinationKeyFile);
            base.ExecuteTool(this.ComputePathToTool(), String.Empty, commandLine.ToString());
            
            byte[] buffer1;
            StrongNameKeyPair keyPair = null;
            byte[] publicKey = null;
            
                using (FileStream stream1 = new FileStream(this.SourceKeyFile, FileMode.Open, FileAccess.Read, FileShare.Read))
                {
                    buffer1 = new byte[(int)stream1.Length];
                    stream1.Read(buffer1, 0, (int)stream1.Length);
                }
                        
            StrongNameKeyPair pair1 = new StrongNameKeyPair(buffer1);
            try
            {
                publicKey = pair1.PublicKey;
                keyPair = pair1;
            }
            catch (ArgumentException)
            {
                publicKey = buffer1;
                
            }

            SHA1Managed sha1Managed = new SHA1Managed();
            byte[] hash = sha1Managed.ComputeHash(publicKey);

            byte[] publicKeyToken = new byte[8]; 
            Array.Copy(hash, hash.Length - publicKeyToken.Length, publicKeyToken, 0, publicKeyToken.Length); 
            Array.Reverse(publicKeyToken, 0, publicKeyToken.Length); 

            System.Text.StringBuilder sb = new System.Text.StringBuilder(16);
            for (int i = 0; i < publicKeyToken.Length; i++)
            {
                sb.Append(publicKeyToken[i].ToString("x2"));
            }
            this.PublicKeyToken = sb.ToString();
        }
    }
}
